package studia.figlewicz.math.library;

import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

public class KrzywaStopyProcentowej implements ZmiennaObjasniajaca {

	private Set<KontraktNaStopeProcentowa> kontrakty = new LinkedHashSet<KontraktNaStopeProcentowa>();
	private LinkedHashMap<Date, Double> krzywa = new LinkedHashMap<Date, Double>();
	private boolean isCalculated = false;
	
	
	// metody
	@Override
	public LinkedHashMap<Date, Double> getPunkty() {
		calculate();
		return krzywa;
	}
	public void dodajKontrakt(KontraktNaStopeProcentowa kontrakt) {
		kontrakty.add(kontrakt);
		isCalculated = false;
	}
	public void usunKontrakt(KontraktNaStopeProcentowa kontrakt) {
		kontrakty.remove(kontrakt);
		isCalculated = false;
	}
	public LinkedHashMap<Date, Double> getPunktyKontraktow() {
		LinkedHashMap<Date, Double> resoult = new LinkedHashMap<Date, Double>();
		LinkedList<KontraktNaStopeProcentowa> posortowane = getSortedKontrakty();
		for (KontraktNaStopeProcentowa kontrakt : posortowane) {
			Date data = new Date(kontrakt.getKoniec().getTime());
			Double wartosc = new Double(kontrakt.getStopa());
			resoult.put(data, wartosc);
		}
		
		return resoult;
	}
	public Date getPoczatek() {
		Date resoult = getKontraktPoczatkowy().getPoczatek();
		return resoult;
	}
	public Date getKoniec() {
		Date resoult = getKontraktKoncowy().getKoniec();
		return resoult;
	}
	
	
	// metody prywatne
	private void calculate() {
		if (!isCalculated)
			recalculate();	
	}
	private void recalculate() {
		LinkedList<KontraktNaStopeProcentowa> listaKontraktow = getSortedKontrakty();
		
		KontraktNaStopeProcentowa poprzedni = null;
		Date poczatek = null;
		if (!listaKontraktow.isEmpty()) {
			
			KontraktNaStopeProcentowa pierwszy = listaKontraktow.get(0);
			poczatek = pierwszy.getPoczatek();
			
			krzywa.put(poczatek, pierwszy.getStopa());

			poprzedni = pierwszy;
			for (int i=1; i<listaKontraktow.size(); i++) {
				KontraktNaStopeProcentowa nastepny = listaKontraktow.get(i);
				
				long L1 = poprzedni.getKoniec().getTime() - poczatek.getTime();
				long L2 = nastepny.getKoniec().getTime() - poczatek.getTime();
				long dL = nastepny.getKoniec().getTime() - poprzedni.getKoniec().getTime();

				double stopaPoprzedni = (1 + poprzedni.getStopa() * Utils.getYearFractionStandard(L1));
				double stopaNastepny = (1 + nastepny.getStopa() * Utils.getYearFractionStandard(L2));
				double stopa = (stopaNastepny / stopaPoprzedni - 1) / Utils.getYearFractionStandard(dL);;

				krzywa.put(poprzedni.getKoniec(), stopa);
				poprzedni = nastepny;
			}
		}
		isCalculated = true;
	}
	private LinkedList<KontraktNaStopeProcentowa> getSortedKontrakty() {
		LinkedList<KontraktNaStopeProcentowa> resoult = new LinkedList<KontraktNaStopeProcentowa>();
		Date maxDate = getKoniec();
		
		Map<Date, KontraktNaStopeProcentowa> kopia = new HashMap<Date, KontraktNaStopeProcentowa>();
		Date temp = maxDate;
		for (KontraktNaStopeProcentowa kontrakt : kontrakty) {
			kopia.put(kontrakt.getKoniec(), kontrakt);
			if (kontrakt.getKoniec().before(temp))
				temp = kontrakt.getKoniec();
		}
		resoult.add(kopia.get(temp));
		kopia.remove(temp);
		
		while (!kopia.isEmpty()) {
			temp = maxDate;
			for (Date data : kopia.keySet())
				if (data.before(temp))
					temp = data;
			resoult.add(kopia.get(temp));
			kopia.remove(temp);
		}
		
		return resoult;
	}
	private KontraktNaStopeProcentowa getKontraktPoczatkowy() {
		KontraktNaStopeProcentowa resoult = null;
		
		Date data = null;
		if (!kontrakty.isEmpty()) {
			resoult = kontrakty.iterator().next();
			data = resoult.getPoczatek();
			for (KontraktNaStopeProcentowa kontrakt : kontrakty) {
				if (data.after(kontrakt.getPoczatek()))
					resoult = kontrakt;
			}
		}
		return resoult;
	}
	private KontraktNaStopeProcentowa getKontraktKoncowy() {
		KontraktNaStopeProcentowa resoult = null;
		
		Date data = null;
		if (!kontrakty.isEmpty()) {
			resoult = kontrakty.iterator().next();
			data = (Date)kontrakty.iterator().next().getKoniec();
			for (KontraktNaStopeProcentowa kontrakt : kontrakty) {
				if (data.before(kontrakt.getKoniec()))
					resoult = kontrakt;
			}
		}
		return resoult;
	}
	
}
